// Vue 3 + TypeScript 前端架构示例代码

// 1. 类型定义文件 types/user.ts
export interface User {
  id: number
  username: string
  email: string
  realName: string
  phone: string
  status: number
  lastLoginTime: string
  createTime: string
  roles: Role[]
}

export interface Role {
  id: number
  roleCode: string
  roleName: string
  description: string
  roleLevel: number
  dataScope: number
  status: number
  createTime: string
  permissions: Permission[]
}

export interface Permission {
  id: number
  permCode: string
  permName: string
  resourceType: string
  resourceUrl?: string
  action: string
  description: string
  parentId?: number
  sortOrder: number
  status: number
}

// API接口类型
export interface UserCreateRequest {
  username: string
  email: string
  password: string
  realName: string
  phone: string
  roleIds: number[]
}

export interface UserUpdateRequest {
  email: string
  realName: string
  phone: string
  status: number
  roleIds?: number[]
}

export interface UserQueryRequest {
  page: number
  size: number
  username?: string
  realName?: string
  status?: number
  orgId?: number
}

// 2. API接口定义 api/user.ts
import { request } from '@/utils/request'
import type { User, UserCreateRequest, UserUpdateRequest, UserQueryRequest } from '@/types/user'

export const userApi = {
  // 获取用户列表
  getUserList(params: UserQueryRequest) {
    return request.get<{
      content: User[]
      page: number
      size: number
      totalElements: number
      totalPages: number
      hasNext: boolean
      hasPrevious: boolean
    }>('/users', { params })
  },

  // 获取用户详情
  getUserDetail(id: number) {
    return request.get<User>(`/users/${id}`)
  },

  // 创建用户
  createUser(data: UserCreateRequest) {
    return request.post<User>('/users', data)
  },

  // 更新用户
  updateUser(id: number, data: UserUpdateRequest) {
    return request.put<User>(`/users/${id}`, data)
  },

  // 删除用户
  deleteUser(id: number) {
    return request.delete(`/users/${id}`)
  },

  // 重置密码
  resetPassword(id: number, newPassword: string) {
    return request.post(`/users/${id}/reset-password`, { newPassword })
  },

  // 批量删除用户
  batchDeleteUsers(ids: number[]) {
    return request.delete('/users/batch', { data: { ids } })
  },

  // 获取用户角色
  getUserRoles(userId: number) {
    return request.get(`/users/${userId}/roles`)
  },

  // 更新用户角色
  updateUserRoles(userId: number, roleIds: number[]) {
    return request.put(`/users/${userId}/roles`, { roleIds })
  }
}

// 3. 权限工具函数 utils/permission.ts
import { usePermissionStore } from '@/stores/permission'

export const usePermission = () => {
  const permissionStore = usePermissionStore()

  /**
   * 检查用户是否有指定权限
   * @param permission 权限编码
   * @returns boolean
   */
  const hasPermission = (permission: string): boolean => {
    return permissionStore.hasPermission(permission)
  }

  /**
   * 检查用户是否有任意一个权限
   * @param permissions 权限编码数组
   * @returns boolean
   */
  const hasAnyPermission = (permissions: string[]): boolean => {
    return permissions.some(permission => hasPermission(permission))
  }

  /**
   * 检查用户是否有所有权限
   * @param permissions 权限编码数组
   * @returns boolean
   */
  const hasAllPermissions = (permissions: string[]): boolean => {
    return permissions.every(permission => hasPermission(permission))
  }

  /**
   * 检查并提示权限不足
   * @param permission 权限编码
   * @returns boolean
   */
  const checkPermission = (permission: string): boolean => {
    if (!hasPermission(permission)) {
      ElMessage.warning('您没有权限执行此操作')
      return false
    }
    return true
  }

  /**
   * 根据数据权限范围过滤数据
   * @param data 数据数组
   * @param dataScope 数据权限范围
   * @param userOrgId 用户机构ID
   * @returns 过滤后的数据
   */
  const filterDataByScope = <T extends { orgId?: number; createUserId?: number }>(
    data: T[],
    dataScope: number,
    userOrgId?: number,
    currentUserId?: number
  ): T[] => {
    switch (dataScope) {
      case 1: // 全部数据
        return data
      case 2: // 本机构及下级
        // 这里需要根据机构层级关系过滤
        return data.filter(item => item.orgId === userOrgId)
      case 3: // 仅本机构
        return data.filter(item => item.orgId === userOrgId)
      case 4: // 仅本人数据
        return data.filter(item => item.createUserId === currentUserId)
      default:
        return []
    }
  }

  return {
    hasPermission,
    hasAnyPermission,
    hasAllPermissions,
    checkPermission,
    filterDataByScope
  }
}

// 4. 权限按钮组件 components/Common/PermissionButton.vue
<template>
  <el-button
    v-if="hasPermission"
    :type="buttonType"
    :size="size"
    :disabled="disabled"
    :loading="loading"
    @click="handleClick"
  >
    <slot />
  </el-button>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { ElMessage } from 'element-plus'
import { usePermission } from '@/utils/permission'

interface Props {
  permission: string
  buttonType?: string
  size?: string
  disabled?: boolean
  loading?: boolean
  confirm?: boolean
  confirmMessage?: string
}

const props = withDefaults(defineProps<Props>(), {
  buttonType: 'primary',
  size: 'default',
  disabled: false,
  loading: false,
  confirm: false,
  confirmMessage: '确定要执行此操作吗？'
})

const emit = defineEmits<{
  click: []
  confirm: []
}>()

const { hasPermission } = usePermission()
const hasPermissionComputed = computed(() => hasPermission(props.permission))

const handleClick = () => {
  if (props.confirm) {
    ElMessageBox.confirm(props.confirmMessage, '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    }).then(() => {
      emit('click')
      emit('confirm')
    }).catch(() => {
      // 用户取消操作
    })
  } else {
    emit('click')
  }
}
</script>

// 5. 用户列表组件 views/UserManagement/UserList.vue
<template>
  <div class="user-management">
    <!-- 页面头部 -->
    <PageHeader 
      title="用户管理" 
      subtitle="管理系统用户信息和权限分配"
      :extra="headerExtra"
    >
      <template #extra>
        <PermissionButton 
          permission="user:create"
          type="primary"
          @click="handleCreate"
        >
          <el-icon><Plus /></el-icon>
          新增用户
        </PermissionButton>
      </template>
    </PageHeader>

    <!-- 搜索表单 -->
    <SearchForm 
      v-model="searchForm"
      :fields="searchFields"
      @search="handleSearch"
      @reset="handleReset"
    />

    <!-- 数据表格 -->
    <DataTable
      v-loading="loading"
      :data="userList"
      :columns="tableColumns"
      :pagination="pagination"
      @page-change="handlePageChange"
      @size-change="handleSizeChange"
    >
      <template #actions="{ row }">
        <el-button 
          type="primary" 
          size="small" 
          text
          @click="handleView(row)"
        >
          查看
        </el-button>
        
        <PermissionButton
          permission="user:update"
          buttonType="primary"
          size="small"
          text
          @click="handleEdit(row)"
        >
          编辑
        </PermissionButton>

        <PermissionButton
          permission="user:reset_password"
          buttonType="warning"
          size="small"
          text
          :confirm="true"
          confirm-message="确定要重置此用户的密码吗？"
          @click="handleResetPassword(row)"
        >
          重置密码
        </PermissionButton>

        <PermissionButton
          permission="user:delete"
          buttonType="danger"
          size="small"
          text
          :confirm="true"
          confirm-message="确定要删除此用户吗？此操作不可恢复。"
          @click="handleDelete(row)"
        >
          删除
        </PermissionButton>
      </template>
    </DataTable>

    <!-- 用户编辑对话框 -->
    <UserEditDialog
      v-model="editDialogVisible"
      :user="currentUser"
      @success="handleEditSuccess"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import PageHeader from '@/components/Common/PageHeader.vue'
import SearchForm from '@/components/Common/SearchForm.vue'
import DataTable from '@/components/Common/DataTable.vue'
import PermissionButton from '@/components/Common/PermissionButton.vue'
import UserEditDialog from './components/UserEditDialog.vue'
import { userApi } from '@/api/user'
import { usePermission } from '@/utils/permission'
import type { User, UserQueryRequest } from '@/types/user'

const router = useRouter()
const { hasPermission } = usePermission()

// 响应式数据
const loading = ref(false)
const userList = ref<User[]>([])
const editDialogVisible = ref(false)
const currentUser = ref<User | null>(null)

// 搜索表单
const searchForm = reactive({
  username: '',
  realName: '',
  status: undefined,
  orgId: undefined
})

// 分页信息
const pagination = reactive({
  page: 1,
  size: 20,
  total: 0
})

// 计算属性
const headerExtra = computed(() => {
  return hasPermission('user:create') ? undefined : []
})

// 表格列定义
const tableColumns = [
  {
    prop: 'username',
    label: '用户名',
    width: 120,
    showOverflowTooltip: true
  },
  {
    prop: 'realName',
    label: '真实姓名',
    width: 120
  },
  {
    prop: 'email',
    label: '邮箱',
    width: 200,
    showOverflowTooltip: true
  },
  {
    prop: 'phone',
    label: '手机号',
    width: 120
  },
  {
    prop: 'status',
    label: '状态',
    width: 80,
    formatter: (row: User) => {
      const statusMap = {
        0: { text: '禁用', type: 'danger' },
        1: { text: '启用', type: 'success' },
        2: { text: '锁定', type: 'warning' }
      }
      const status = statusMap[row.status as keyof typeof statusMap]
      return h('el-tag', { type: status?.type }, status?.text)
    }
  },
  {
    prop: 'roles',
    label: '角色',
    width: 200,
    formatter: (row: User) => {
      return row.roles.map(role => role.roleName).join('、')
    }
  },
  {
    prop: 'lastLoginTime',
    label: '最后登录时间',
    width: 180,
    formatter: (row: User) => {
      return row.lastLoginTime ? new Date(row.lastLoginTime).toLocaleString() : '-'
    }
  },
  {
    prop: 'createTime',
    label: '创建时间',
    width: 180,
    formatter: (row: User) => {
      return new Date(row.createTime).toLocaleString()
    }
  },
  {
    label: '操作',
    width: 280,
    slotName: 'actions'
  }
]

// 搜索字段定义
const searchFields = [
  {
    prop: 'username',
    label: '用户名',
    type: 'input',
    placeholder: '请输入用户名'
  },
  {
    prop: 'realName',
    label: '真实姓名',
    type: 'input',
    placeholder: '请输入真实姓名'
  },
  {
    prop: 'status',
    label: '状态',
    type: 'select',
    placeholder: '请选择状态',
    options: [
      { label: '启用', value: 1 },
      { label: '禁用', value: 0 },
      { label: '锁定', value: 2 }
    ]
  },
  {
    prop: 'orgId',
    label: '所属机构',
    type: 'tree-select',
    placeholder: '请选择机构',
    load: () => loadOrgTree()
  }
]

// 方法
const loadUserList = async () => {
  loading.value = true
  try {
    const params: UserQueryRequest = {
      page: pagination.page,
      size: pagination.size,
      ...searchForm
    }
    
    const response = await userApi.getUserList(params)
    userList.value = response.content
    pagination.total = response.totalElements
  } catch (error) {
    ElMessage.error('加载用户列表失败')
  } finally {
    loading.value = false
  }
}

const loadOrgTree = async () => {
  // 加载机构树
  // return orgApi.getOrgTree()
}

const handleSearch = () => {
  pagination.page = 1
  loadUserList()
}

const handleReset = () => {
  Object.assign(searchForm, {
    username: '',
    realName: '',
    status: undefined,
    orgId: undefined
  })
  handleSearch()
}

const handlePageChange = (page: number) => {
  pagination.page = page
  loadUserList()
}

const handleSizeChange = (size: number) => {
  pagination.size = size
  pagination.page = 1
  loadUserList()
}

const handleCreate = () => {
  router.push('/users/create')
}

const handleView = (row: User) => {
  router.push(`/users/${row.id}`)
}

const handleEdit = (row: User) => {
  currentUser.value = row
  editDialogVisible.value = true
}

const handleResetPassword = async (row: User) => {
  try {
    await userApi.resetPassword(row.id, '123456')
    ElMessage.success('密码重置成功')
  } catch (error) {
    ElMessage.error('密码重置失败')
  }
}

const handleDelete = async (row: User) => {
  try {
    await userApi.deleteUser(row.id)
    ElMessage.success('删除成功')
    loadUserList()
  } catch (error) {
    ElMessage.error('删除失败')
  }
}

const handleEditSuccess = () => {
  editDialogVisible.value = false
  loadUserList()
}

// 生命周期
onMounted(() => {
  loadUserList()
})
</script>

<style scoped>
.user-management {
  padding: 20px;
}
</style>

// 6. 用户编辑对话框组件 views/UserManagement/components/UserEditDialog.vue
<template>
  <el-dialog
    v-model="dialogVisible"
    :title="isEdit ? '编辑用户' : '新增用户'"
    width="600px"
    @close="handleClose"
  >
    <el-form
      ref="formRef"
      :model="form"
      :rules="rules"
      label-width="100px"
    >
      <el-form-item label="用户名" prop="username">
        <el-input 
          v-model="form.username" 
          :disabled="isEdit"
          placeholder="请输入用户名"
        />
      </el-form-item>
      
      <el-form-item label="真实姓名" prop="realName">
        <el-input 
          v-model="form.realName" 
          placeholder="请输入真实姓名"
        />
      </el-form-item>
      
      <el-form-item label="邮箱" prop="email">
        <el-input 
          v-model="form.email" 
          placeholder="请输入邮箱"
        />
      </el-form-item>
      
      <el-form-item label="手机号" prop="phone">
        <el-input 
          v-model="form.phone" 
          placeholder="请输入手机号"
        />
      </el-form-item>
      
      <el-form-item 
        v-if="!isEdit" 
        label="密码" 
        prop="password"
      >
        <el-input 
          v-model="form.password" 
          type="password"
          placeholder="请输入密码"
        />
      </el-form-item>
      
      <el-form-item label="状态" prop="status">
        <el-radio-group v-model="form.status">
          <el-radio :label="1">启用</el-radio>
          <el-radio :label="0">禁用</el-radio>
        </el-radio-group>
      </el-form-item>
      
      <el-form-item label="分配角色" prop="roleIds">
        <el-select 
          v-model="form.roleIds" 
          multiple
          placeholder="请选择角色"
          style="width: 100%"
        >
          <el-option
            v-for="role in roleList"
            :key="role.id"
            :label="role.roleName"
            :value="role.id"
          />
        </el-select>
      </el-form-item>
    </el-form>
    
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="handleClose">取消</el-button>
        <el-button 
          type="primary" 
          :loading="loading"
          @click="handleSubmit"
        >
          {{ isEdit ? '更新' : '创建' }}
        </el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { ref, computed, watch, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import { roleApi } from '@/api/role'
import { userApi } from '@/api/user'
import type { User, UserCreateRequest, UserUpdateRequest } from '@/types/user'

interface Props {
  modelValue: boolean
  user: User | null
}

interface Emits {
  (e: 'update:modelValue', value: boolean): void
  (e: 'success'): void
}

const props = defineProps<Props>()
const emit = defineEmits<Emits>()

const formRef = ref()
const loading = ref(false)
const roleList = ref([])

// 计算属性
const dialogVisible = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value)
})

const isEdit = computed(() => !!props.user?.id)

// 表单数据
const form = ref<UserCreateRequest>({
  username: '',
  realName: '',
  email: '',
  phone: '',
  password: '',
  status: 1,
  roleIds: []
})

// 表单验证规则
const rules = {
  username: [
    { required: true, message: '请输入用户名', trigger: 'blur' },
    { min: 3, max: 20, message: '用户名长度3-20个字符', trigger: 'blur' }
  ],
  realName: [
    { required: true, message: '请输入真实姓名', trigger: 'blur' }
  ],
  email: [
    { required: true, message: '请输入邮箱', trigger: 'blur' },
    { type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
  ],
  password: [
    { required: true, message: '请输入密码', trigger: 'blur' },
    { min: 6, message: '密码长度不能少于6位', trigger: 'blur' }
  ]
}

// 加载角色列表
const loadRoleList = async () => {
  try {
    const response = await roleApi.getRoleList({ page: 1, size: 1000 })
    roleList.value = response.content
  } catch (error) {
    ElMessage.error('加载角色列表失败')
  }
}

// 初始化表单数据
const initForm = () => {
  if (props.user) {
    form.value = {
      username: props.user.username,
      realName: props.user.realName,
      email: props.user.email,
      phone: props.user.phone,
      password: '',
      status: props.user.status,
      roleIds: props.user.roles.map(role => role.id)
    }
  } else {
    form.value = {
      username: '',
      realName: '',
      email: '',
      phone: '',
      password: '',
      status: 1,
      roleIds: []
    }
  }
}

// 提交表单
const handleSubmit = async () => {
  if (!formRef.value) return
  
  try {
    await formRef.value.validate()
    loading.value = true
    
    if (isEdit.value) {
      // 更新用户
      const updateData: UserUpdateRequest = {
        email: form.value.email,
        realName: form.value.realName,
        phone: form.value.phone,
        status: form.value.status,
        roleIds: form.value.roleIds
      }
      await userApi.updateUser(props.user!.id, updateData)
      ElMessage.success('更新成功')
    } else {
      // 创建用户
      await userApi.createUser(form.value)
      ElMessage.success('创建成功')
    }
    
    emit('success')
    handleClose()
  } catch (error) {
    ElMessage.error(isEdit.value ? '更新失败' : '创建失败')
  } finally {
    loading.value = false
  }
}

// 关闭对话框
const handleClose = () => {
  dialogVisible.value = false
  nextTick(() => {
    formRef.value?.resetFields()
  })
}

// 监听对话框显示状态
watch(() => props.modelValue, (visible) => {
  if (visible) {
    initForm()
    loadRoleList()
  }
})
</script>

<style scoped>
.dialog-footer {
  text-align: right;
}
</style>

// 7. 状态管理 stores/user.ts
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { userApi } from '@/api/user'
import type { User, UserQueryRequest } from '@/types/user'

export const useUserStore = defineStore('user', () => {
  const userList = ref<User[]>([])
  const currentUser = ref<User | null>(null)
  const loading = ref(false)

  // 分页信息
  const pagination = ref({
    page: 1,
    size: 20,
    total: 0
  })

  // 获取用户列表
  const fetchUserList = async (params: UserQueryRequest) => {
    loading.value = true
    try {
      const response = await userApi.getUserList(params)
      userList.value = response.content
      pagination.value = {
        page: response.page,
        size: response.size,
        total: response.totalElements
      }
    } catch (error) {
      console.error('获取用户列表失败:', error)
      throw error
    } finally {
      loading.value = false
    }
  }

  // 获取用户详情
  const fetchUserDetail = async (id: number) => {
    try {
      const user = await userApi.getUserDetail(id)
      currentUser.value = user
      return user
    } catch (error) {
      console.error('获取用户详情失败:', error)
      throw error
    }
  }

  // 创建用户
  const createUser = async (data: any) => {
    try {
      const user = await userApi.createUser(data)
      userList.value.unshift(user)
      return user
    } catch (error) {
      console.error('创建用户失败:', error)
      throw error
    }
  }

  // 更新用户
  const updateUser = async (id: number, data: any) => {
    try {
      const user = await userApi.updateUser(id, data)
      const index = userList.value.findIndex(u => u.id === id)
      if (index !== -1) {
        userList.value[index] = user
      }
      if (currentUser.value?.id === id) {
        currentUser.value = user
      }
      return user
    } catch (error) {
      console.error('更新用户失败:', error)
      throw error
    }
  }

  // 删除用户
  const deleteUser = async (id: number) => {
    try {
      await userApi.deleteUser(id)
      userList.value = userList.value.filter(u => u.id !== id)
    } catch (error) {
      console.error('删除用户失败:', error)
      throw error
    }
  }

  return {
    userList,
    currentUser,
    loading,
    pagination,
    fetchUserList,
    fetchUserDetail,
    createUser,
    updateUser,
    deleteUser
  }
})

// 8. 权限路由守卫 router/permissionGuard.ts
import type { Router } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { usePermissionStore } from '@/stores/permission'

export const setupPermissionGuard = (router: Router) => {
  router.beforeEach(async (to, from, next) => {
    const authStore = useAuthStore()
    const permissionStore = usePermissionStore()

    // 检查是否需要登录
    if (to.meta.requiresAuth !== false && !authStore.isLoggedIn) {
      next('/login')
      return
    }

    // 如果已登录但没有权限信息，尝试获取
    if (authStore.isLoggedIn && permissionStore.userPermissions.length === 0) {
      try {
        await authStore.fetchProfile()
        permissionStore.setUserPermissions(authStore.permissions)
      } catch (error) {
        next('/login')
        return
      }
    }

    // 检查页面权限
    if (to.meta.permission && !permissionStore.hasPermission(to.meta.permission as string)) {
      ElMessage.warning('您没有权限访问此页面')
      next('/403')
      return
    }

    next()
  })
}
